#ifndef UTILS_BASIC_IO_NOTIFIER_H_INCLUDED
#define UTILS_BASIC_IO_NOTIFIER_H_INCLUDED

#include <sys/epoll.h>
#include <sys/eventfd.h>
#include <unistd.h>
#include <errno.h>  // errno
#include <stdint.h> // uint64_t, uint32_t

#include <utils/noncopyable.h>
#include <utils/system_exception.h>

namespace utils
{

class basic_io_notifier
    : utils::noncopyable
{
public:
    basic_io_notifier()
        : epfd_(::epoll_create1(0))
    {
        if(epfd_ < 0)
        {
            throw utils::system_exception(errno);
        }
    }
    ~basic_io_notifier()
    {
        ::close(epfd_);
    }

    template <uint32_t Event>
    bool add_event(int fd, void * data = 0)
    {
        ::epoll_event ev;
        ev.events   = Event | EPOLLRDHUP;
        ev.data.ptr = data;
        return ::epoll_ctl(epfd_, EPOLL_CTL_ADD, fd, &ev) != -1;
    }
    template <uint32_t Event>
    bool mod_event(int fd, void * data = 0)
    {
        ::epoll_event ev;
        ev.events   = Event;
        ev.data.ptr = data;
        return ::epoll_ctl(epfd_, EPOLL_CTL_MOD, fd, &ev) != -1;
    }
    bool del_event(int fd)
    {
        ::epoll_event ev;
        ev.events   = EPOLLRDHUP;
        ev.data.ptr = 0;
        return ::epoll_ctl(epfd_, EPOLL_CTL_DEL, fd, &ev) != -1;
    }

    int wait(::epoll_event * events, size_t count, int timeout) const
    {
        return ::epoll_wait(epfd_, events, count, timeout);
    }

private:
    int const epfd_;
};

}

#endif // UTILS_BASIC_IO_NOTIFIER_H_INCLUDED
